package com.group4.datafactorybackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group4.datafactorybackend.common.DataFactoryConstantPool;
import com.group4.datafactorybackend.common.R;
import com.group4.datafactorybackend.common.enums.MyEnumClass;
import com.group4.datafactorybackend.common.enums.ResultCodeEnum;
import com.group4.datafactorybackend.common.exception.DataFactoryException;
import com.group4.datafactorybackend.entity.DO.DafDcDO;
import com.group4.datafactorybackend.entity.DO.DataCriterionDO;
import com.group4.datafactorybackend.entity.DO.DcStopwatchDO;
import com.group4.datafactorybackend.entity.DTO.BatchReleaseOrOutageDTO;
import com.group4.datafactorybackend.entity.DTO.DataCriterionDTO;
import com.group4.datafactorybackend.entity.DTO.DataCriterionParameterDTO;
import com.group4.datafactorybackend.entity.VO.DataCriterionExcelVO;
import com.group4.datafactorybackend.mapper.DafDcMapper;
import com.group4.datafactorybackend.mapper.DataCriterionMapper;
import com.group4.datafactorybackend.mapper.DcStopwatchMapper;
import com.group4.datafactorybackend.service.DataCriterionService;
import com.group4.datafactorybackend.util.CodeUtil;
import com.group4.datafactorybackend.util.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xin
 * @date 2022/7/27 13:40
 */
@Service
@Slf4j
public class DataCriterionServiceImpl extends ServiceImpl<DataCriterionMapper, DataCriterionDO> implements DataCriterionService{

    @Autowired
    private DataCriterionMapper dataCriterionMapper;

    @Autowired
    private DafDcMapper dafDcMapper;

    @Autowired
    private DcStopwatchMapper dcStopwatchMapper;

    /**
     * @author 李泓静
     * @param dcCode 数据标准编号
     * @return R
     * @description 查看数据标准详情
     */
    @Override
    public R<?> getDataCriterionDetail(String dcCode) {
        LambdaQueryWrapper<DataCriterionDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DataCriterionDO::getDcCode,dcCode);
        DataCriterionDO dataCriterion = dataCriterionMapper.selectOne(lambdaQueryWrapper);
        if(dataCriterion!=null){
            return R.Success(ResultCodeEnum.SUCCESS,dataCriterion);
        }
        return R.Failed(ResultCodeEnum.REQUEST_OUT_OVERTIME.getCode(),ResultCodeEnum.REQUEST_OUT_OVERTIME.getMessage());

    }

    /**
     * @author 邹代鑫
     * @param dcCode 数据标准编号
     * @description 删除数据标准目录
     **/
    @Override
    public void deleteCriterionDetail(String dcCode) {
        //删除数据标准目录
        LambdaQueryWrapper<DataCriterionDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DataCriterionDO::getDcCode, dcCode);
        int delete = this.dataCriterionMapper.delete(wrapper);
        if (delete == 0){
            throw new DataFactoryException(ResultCodeEnum.REQUEST_PARAM_ERROR.getMessage());
        }
    }

    /**
     * @author 卑微小峰
     * @param batchReleaseOrOutageDTO （批量）发布/停用接收参数实体类
     * @return R
     * @description 发布/停用数据标准
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> releaseOrOutage(BatchReleaseOrOutageDTO batchReleaseOrOutageDTO) {
        Integer dcStatus = batchReleaseOrOutageDTO.getStatus();
        List<String> dcCodeList = batchReleaseOrOutageDTO.getCodeList();

        // 判断批量（停用）操作中是否存在未发布的数据标准目录
        if (dcStatus.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
            LambdaQueryWrapper<DataCriterionDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataCriterionDO::getDcStatus, MyEnumClass.StatusEnum.NOT_RELEASE.getCode())
                    .in(DataCriterionDO::getDcCode, dcCodeList);
            int result = dataCriterionMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_NOT_RELEASE.getCode(), "存在未发布的数据标准目录");
            }
        }
        // 判断批量（发布）操作中是否存在已发布的数据标准目录
        if (dcStatus.equals(MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())) {
            LambdaQueryWrapper<DataCriterionDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataCriterionDO::getDcStatus, MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())
                    .in(DataCriterionDO::getDcCode, dcCodeList);
            int result = dataCriterionMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_HAVE_RELEASE.getCode(), "存在已发布的数据标准目录");
            }
        }

        // 判断是否含有被引用的数据标准目录
        int bool = 0;
        LambdaQueryWrapper<DafDcDO> isBeAdoptedByDataAssertFieldWrapper = new LambdaQueryWrapper<>();
        for (String dcCode : dcCodeList) {
            if (bool != 0) {
                return R.Failed(ResultCodeEnum.BEING_CITED.getCode(),"数据标准目录：" + dcCode + ResultCodeEnum.BEING_CITED.getMessage());
            }else {
                // 判断是否存在被未停用的数据资产字段的引用
                isBeAdoptedByDataAssertFieldWrapper.eq(DafDcDO::getDcCode,dcCode)
                        .eq(DafDcDO::getIsDisable, MyEnumClass.QuoteStatusEnum.OPEN_QUOTE.getCode());
                bool = dafDcMapper.selectCount(isBeAdoptedByDataAssertFieldWrapper);
            }
        }

        // 没有数据标准目录正在被引用：
        // 判断是否引用码表，如果引用，则（停用：关闭码表引用   发布：开启码表引用），未引用，则直接停用
        try {
            LambdaQueryWrapper<DcStopwatchDO> isQuoteStopwatchWrapper = new LambdaQueryWrapper<>();
            LambdaUpdateWrapper<DcStopwatchDO> updateQuoteStopwatchStatusWrapper = new LambdaUpdateWrapper<>();
            for (String dcCode : dcCodeList) {
                // 1、判断数据标准目录是否引用了码表
                isQuoteStopwatchWrapper.eq(DcStopwatchDO::getDcCode,dcCode);
                int num = dcStopwatchMapper.selectCount(isQuoteStopwatchWrapper);
                // 2、返回值大于0表示引用了码表，需要修改引用状态，再修改发布状态（不是解除引用,修改引用状态）,否则直接发布
                if (num > 0) {
                    if (dcStatus.equals(MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())) {
                        updateQuoteStopwatchStatusWrapper.eq(DcStopwatchDO::getDcCode,dcCode)
                                .set(DcStopwatchDO::getIsDisable, MyEnumClass.QuoteStatusEnum.OPEN_QUOTE.getCode());
                        dcStopwatchMapper.update(null, updateQuoteStopwatchStatusWrapper);
                    }else if (dcStatus.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
                        updateQuoteStopwatchStatusWrapper.eq(DcStopwatchDO::getDcCode, dcCode)
                                .set(DcStopwatchDO::getIsDisable, MyEnumClass.QuoteStatusEnum.CLOSE_QUOTE.getCode());
                        dcStopwatchMapper.update(null,updateQuoteStopwatchStatusWrapper);
                    }else {
                        return R.Failed("错误的状态值");
                    }

                }
            }
            // 3、发布数据标准（修改数据标准状态）
            LambdaUpdateWrapper<DataCriterionDO> releaseOrOutageWrapper = new LambdaUpdateWrapper<>();
            releaseOrOutageWrapper.in(DataCriterionDO::getDcCode,dcCodeList)
                    .set(DataCriterionDO::getDcStatus,dcStatus);
            int result = dataCriterionMapper.update(null,releaseOrOutageWrapper);
            if (result <= 0) {
                return R.Failed(ResultCodeEnum.OPERATION_FAILED);
            }
        } catch (Exception e) {
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 李泓静
     * @param dataCriterion xxx
     * @return int
     * @description 编辑数据标准
     */
    @Override
    @Transactional(rollbackFor  = Exception.class)
    public R<?> updateDataCriterion(DataCriterionDO dataCriterion) {
        LambdaUpdateWrapper<DataCriterionDO> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(DataCriterionDO::getDcCode,dataCriterion.getDcCode());
        int result = dataCriterionMapper.update(dataCriterion,wrapper);
        System.out.println(dataCriterion.getUpdateTime());
        if (result <= 0) {
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 邹代鑫
     * @param file 文件
     * @return R
     * @description 导入数据标准
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> importExcel(MultipartFile file) {
        try {
            //解析表格
            List<DataCriterionExcelVO> dataCriterionExcelList = ExcelUtils.importExcel(file, 0,1,DataCriterionExcelVO.class);
            // 过滤掉不必要的数据集合
            for (int i = 0; i < dataCriterionExcelList.size(); i++) {
                DataCriterionExcelVO dataCriterionExcelVO = dataCriterionExcelList.get(i);
                if (StringUtils.isBlank(dataCriterionExcelVO.getDcChName())){
                    dataCriterionExcelList.remove(i);
                    i--;
                }
            }

            //复制数据给DataCriterionDO,插入数据库
            for (DataCriterionExcelVO dataCriterionExcelVO : dataCriterionExcelList) {
                DataCriterionDTO criterionDTO = new DataCriterionDTO();
                BeanUtils.copyProperties(dataCriterionExcelVO,criterionDTO);
                //存储到数据库
                this.addDataCriterion(criterionDTO);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return R.Success(ResultCodeEnum.SUCCESS,null);
    }

    /**
     * @author 章珑赢
     * @param parameterDTO 查询数据标准目录列表接收数据实体类
     * @return R
     * @description 查询数据标准目录列表
     */
    @Override
    public R<?> dataCriterionList(DataCriterionParameterDTO parameterDTO) {
        //分页类
        Page<DataCriterionDO>  page = new Page<>(parameterDTO.getPageNum(), parameterDTO.getPageSize());
        //条件构造器类
        LambdaQueryWrapper<DataCriterionDO> wrapper = new LambdaQueryWrapper<>();
        //StringUtils.isNotBlank(pageCode.getStopwatchName())这句的意思是getStopwatchChName不为空就执行后面代码，为空就不再执行
        //中文名称模糊查询
        wrapper.like(StringUtils.isNotBlank(parameterDTO.getDcChName()), DataCriterionDO::getDcChName, parameterDTO.getDcChName())
                //英文名称模糊查询
                .like(StringUtils.isNotBlank(parameterDTO.getDcEnName()), DataCriterionDO::getDcEnName, parameterDTO.getDcEnName())
                //来源机构查询
                .eq(StringUtils.isNotBlank(parameterDTO.getDcSourceStructure()), DataCriterionDO::getDcSourceStructure, parameterDTO.getDcSourceStructure())
                //标准状态
                .eq(StringUtils.isNotBlank(parameterDTO.getDcStatus()), DataCriterionDO::getDcStatus, parameterDTO.getDcStatus())
                //标准编号
                .eq(StringUtils.isNotBlank(parameterDTO.getDcCode()), DataCriterionDO::getDcCode, parameterDTO.getDcCode())
                //时间和状态进行排序
                .orderByAsc(DataCriterionDO::getDcStatus).orderByDesc(DataCriterionDO::getUpdateTime);
        Page<DataCriterionDO> dataCriterionDoPage = dataCriterionMapper.selectPage(page, wrapper);
        return R.Success(ResultCodeEnum.SUCCESS, dataCriterionDoPage);
    }

    /**
     * @author 章珑赢
     * @param dataCriterionDTO 新增数据标准表实体类
     * @return R
     * @description 新增数据标准
     */
    @Override
    @Transactional(rollbackFor  = Exception.class)
    public R<?> addDataCriterion(DataCriterionDTO dataCriterionDTO) {
        DataCriterionDO dataCriterionDO = new DataCriterionDO();
        BeanUtils.copyProperties(dataCriterionDTO,dataCriterionDO);
        LambdaUpdateWrapper<DataCriterionDO> dataCriterionWrapper = new LambdaUpdateWrapper<>();
        //数据验证数据库是否存在中文重复
        dataCriterionWrapper.eq(DataCriterionDO::getDcChName,dataCriterionDO.getDcChName());
        DataCriterionDO isExistChName = dataCriterionMapper.selectOne(dataCriterionWrapper);
        if(isExistChName!=null){
            return R.Failed(ResultCodeEnum.CN_NAME_REPEAT);
        }
        //数据验证数据库是否存在英文重复
        dataCriterionWrapper.clear();
        dataCriterionWrapper.eq(DataCriterionDO::getDcEnName,dataCriterionDO.getDcEnName());
        DataCriterionDO isExistEnName = dataCriterionMapper.selectOne(dataCriterionWrapper);
        if(isExistEnName!=null){
            return R.Failed(ResultCodeEnum.EN_NAME_REPEAT);
        }
        // updater：卑微小峰
        // 生成数据标准目录编号
        // dataCriterionDO.getId()：使用MyBatisPlus添加数据会自动返回ID在执行操作的实体类（DO）中
        this.dataCriterionMapper.insert(dataCriterionDO);
        String dcCode = CodeUtil.getCode(DataFactoryConstantPool.DATA_CRITERION_CODE_PREFIX,String.valueOf(dataCriterionDO.getId()));
        // 回填编号
        System.out.println(dataCriterionDO.getCreateTime());
        LambdaUpdateWrapper<DataCriterionDO> updateDcCodeWrapper = new LambdaUpdateWrapper<>();
        updateDcCodeWrapper.eq(DataCriterionDO::getId,dataCriterionDO.getId())
                .set(DataCriterionDO::getDcCode, dcCode);
        int result = dataCriterionMapper.update(null,updateDcCodeWrapper);
        System.out.println(dataCriterionDO.getCreateTime());
        if (result > 0){
            return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
        }
        return R.Failed(ResultCodeEnum.OPERATION_FAILED);
    }

    /**
     * @author 邹代鑫
     * @param response 请求响应
     * @return int
     * @description 导出标准表格
     */
    @Override
    public R<?> exportExcel(HttpServletResponse response) {
        try {
            //设置下载文件名
            String fileName = URLEncoder.encode("数据标准目录", "UTF-8");

            List<DataCriterionExcelVO> dataCriterion = new ArrayList<>();
            //创建标准对象
            DataCriterionExcelVO d1 = new DataCriterionExcelVO();
            DataCriterionExcelVO d2 = new DataCriterionExcelVO();
            DataCriterionExcelVO d3 = new DataCriterionExcelVO();
            DataCriterionExcelVO d4 = new DataCriterionExcelVO();

            //对象添加数据
            d1.setDcChName("企业类型");
            d1.setDcEnName("firmType");
            d1.setDcDataNull("不可为空");
            d1.setDcSourceStructure("数宜信/技术中心");
            d1.setDcType("Enum");
            d1.setDcStopwatchName("MZB00001");

            d2.setDcChName("企业名称");
            d2.setDcEnName("name");
            d2.setDcDataNull("不可为空");
            d2.setDcSourceStructure("数宜信/数据中心");
            d2.setDcType("String");
            d2.setDcLength(100L);

            d3.setDcChName("员工人数");
            d3.setDcEnName("empNum");
            d3.setDcDataNull("可为空");
            d3.setDcSourceStructure("数宜信/技术中心");
            d3.setDcType("Int");
            d3.setDcMinValue("1");
            d3.setDcMaxValue("999999");

            d4.setDcChName("注册金额");
            d4.setDcEnName("regAmount");
            d4.setDcDataNull("可为空");
            d4.setDcSourceStructure("数宜信/数据中心");
            d4.setDcType("Float");
            d4.setDcPrecision(2.0);
            d4.setDcMinValue("0");
            d4.setDcMaxValue("999999999");

            dataCriterion.add(d1);
            dataCriterion.add(d2);
            dataCriterion.add(d3);
            dataCriterion.add(d4);

            //导出表格
            ExcelUtils.exportExcel(dataCriterion,null,"测试",DataCriterionExcelVO.class,fileName,true,response);
            return R.Success(ResultCodeEnum.SUCCESS,null);
        } catch (IOException e) {
            e.printStackTrace();
            return R.Failed(ResultCodeEnum.EXCEL_EXPORT_FAILED.getMessage());
        }
    }

}
